#include "document.h"
#include "commands.h"
#include "tools/pen_tool.h"
#include "tools/eraser_tool.h"

#include <QDebug>

class Tool;

Document::Document(QWidget* parent): QGraphicsView(parent)
{
    // TODO: Magic string!
    m_fileName = "Unnamed";
    m_currentTool = 0;
    m_dirty = false;
    m_pages = new QList<Page*>();
    m_scale = 1;
    m_undoStack = new KUndoStack(this);
    configureScene();
    setPenTool();
}

void Document::configureScene()
{
    setScene(new QGraphicsScene(this));
    this->scene()->setBackgroundBrush(QBrush(Qt::gray));
    setRenderHint(QPainter::Antialiasing);
}

void Document::insertPage(int index, Page* page)
{
    if (index <= m_pages->count()) {
        m_pages->insert(index, page);
        scene()->addItem(page);
        rePositionPages();
    }
}

void Document::insertPage(Page* indexPage, Page* page)
{
    int index = m_pages->indexOf(indexPage);
    if (index > -1) {
        insertPage(index + 1, page);
    }
}

void Document::addNewPage()
{
    insertPage(m_pages->size(), new Page(this));
}

void Document::addNewPage(int index)
{
    insertPage(index, new Page(this));
}

void Document::addNewPage(Page *page)
{
    qDebug() << "Page Param";
    insertPage(page, new Page(this));
}

void Document::rePositionPages()
{
    Page *currentPage;

    // These are used to define the needed sceneRect to display all pages.
    qreal maxX = 0;
    qreal maxY = 0;

    for (int i = 0; i < m_pages->size(); i++) {
        currentPage = m_pages->at(i);

        // Move every page by half its width to the left so they all center-align on the y-axis.
        qreal x = currentPage->boundingRect().width() / -2;

        if (i == 0) {
            // First page is at the very top.
            currentPage->setPos(x, 0);

        } else {
            // Get the bottom position of the previous page and add a margin of 15px.
            qreal y = m_pages->at(i-1)->pos().y() + m_pages->at(i-1)->boundingRect().bottom() + 15;
            currentPage->setPos(x, y);
        }
        currentPage->repositionChildren();

        // Check if this page proves the new maximum width.
        maxX = qMax(currentPage->scenePos().x() + currentPage->boundingRect().width(), maxX);
    }

    // Maximum Y is given by the last page.
    maxY = qMax(m_pages->last()->scenePos().y() + m_pages->last()->boundingRect().height(), maxY);
    scene()->setSceneRect(-maxX, 0, maxX*2, maxY);
    setSceneRect(scene()->sceneRect());

}

void Document::mouseMoveEvent(QMouseEvent* event)
{
    m_currentTool->mouseMoveEvent(event, this);
    QGraphicsView::mouseMoveEvent(event);
}

void Document::mousePressEvent(QMouseEvent* event)
{
    m_currentTool->mousePressEvent(event, this);
    QGraphicsView::mousePressEvent(event);
}

void Document::mouseReleaseEvent(QMouseEvent* event)
{
    m_currentTool->mouseReleaseEvent(event, this);
    QGraphicsView::mouseReleaseEvent(event);
}

void Document::mouseDoubleClickEvent(QMouseEvent* event)
{
    m_currentTool->mouseDoubleClickEvent(event, this);
    QGraphicsView::mouseDoubleClickEvent(event);
}

void Document::tabletEvent(QTabletEvent* event)
{
    m_currentTool->tabletEvent(event, this);
    QWidget::tabletEvent(event);
}

Page* Document::pageAt(const QPointF point)
{
    // null when the page list is empty.
    if (m_pages->isEmpty()) {
        return 0;
    }

    // Iterate over the items in the scene, that are at the given point.
    QListIterator<QGraphicsItem*> iter(scene()->items(point));
    QGraphicsItem *current;
    while (iter.hasNext()) {
        current = iter.next();
        // Check if the item is a page and return it when it is
        if (current->type() == Page::Type) {
            return qgraphicsitem_cast<Page*>(current);
        }
    }

    // No page was found in the scene at the given point, return null
    return 0;
}

bool Document::close()
{
    // TODO: Ask for and save changes when dirty.
    if (m_dirty) {
        return false;
    } else {
        return true;
    }
}

void Document::removePage(Page* page)
{
    if (m_pages->size() == 1) {
        addNewPage();
    }
    pushUndoCommand(new RemovePageCommand(page, this));
}

void Document::movePageDown(Page* page)
{
    int index = m_pages->indexOf(page);
    if (index == m_pages->count() - 1) {
        return;
    }
    m_pages->swap(index, index + 1);
    rePositionPages();
}

void Document::movePageUp(Page* page)
{
    int index = m_pages->indexOf(page);
    if (index == 0) {
        return;
    }
    m_pages->swap(index, index - 1);
    rePositionPages();
}

void Document::redo()
{
    m_undoStack->redo();
}

void Document::undo()
{
    m_undoStack->undo();
}

void Document::pushUndoCommand(QUndoCommand* cmd)
{
    m_undoStack->push(cmd);
}

void Document::setEraserTool()
{
    unsetTool();
    m_currentTool = new Eraser(this);
}

void Document::setPenTool()
{
    unsetTool();
    m_currentTool = new Pen(this);
}

void Document::unsetTool()
{
    if (m_currentTool)
    {
        delete m_currentTool;
        m_currentTool = 0;
    }
}

void Document::setScale(qreal level)
{
    if (level == m_scale) {
        return;
    }
    m_scalePrevious = m_scale;
    m_scale = level;
    qreal scaleFactor = m_scale / m_scalePrevious;

    QListIterator<Page*> iter(*m_pages);
    Page *current;
    while (iter.hasNext()) {
        current = iter.next();
        current->setScale(m_scalePrevious, m_scale, scaleFactor);
    }

    rePositionPages();
}

Page* Document::currentPage()
{
    QListIterator<QGraphicsItem*> iter(items(geometry().center()));
    QGraphicsItem *current;
    while (iter.hasNext()) {
        current = iter.next();
        if (current->type() == Page::Type) {
            return (Page*)current;
        }
    }
    return 0;
}
